package com.cf.log.core;

import com.cf.log.core.domain.Log;
import com.cf.spel.SpELService;
import com.cf.util.ObjectJsonUtil;
import com.cf.util.SpringBeanUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import java.util.stream.Collectors;

/**
 * cf-game-ZLimitAspect
 * 接口频率访问限制切面
 *
 * @author <a href="2428922347@qq.com">Zhu mingming</a>
 * @info
 * @since 2018/4/23 上午 10:45
 */
@Slf4j
@Aspect
@Order(-110)
public class LogAspect {

    @Autowired
    private SpELService spELService;

    @Autowired
    private LogPersistenceService logPersistenceService;

    /**
     * 方法执行时
     */
    @Pointcut("@annotation(ZLog)")
    public void ZLogAspect() {
    }

    @Around("@annotation(ZLog)")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        Log log = log(pjp);
        boolean resultCode = false;
        try {
            Object proceed = pjp.proceed();
            log.setResult(ObjectJsonUtil.toString(proceed));
            resultCode = true;
            return proceed;
        } catch (Throwable throwable) {
            throw throwable;
        } finally {
            log.setEndTime(new Date());
            log.setSuccess(resultCode);
            logPersistenceService.persistenceLog(log);
        }
    }

    private Log log(ProceedingJoinPoint pjp) throws Throwable {
        Log log = new Log();
        //拦截的方法
        Method method = ((MethodSignature) pjp.getSignature()).getMethod();
        ZLog logAnnotation = method.getAnnotation(ZLog.class);
        log.setActionTime(new Date());
        log.setMethodName(method.getName());

        //拦截的放参数类型
        Object[] parameterArgs = pjp.getArgs();
        log.setName(spELService.getSpELValue(method, logAnnotation.name(), String.class, parameterArgs));
        log.setParameter(ObjectJsonUtil.toString(Arrays.asList(parameterArgs).stream().filter(s -> {
            return !(s instanceof ServletRequest || s instanceof ServletResponse);
        }).collect(Collectors.toList())));
        log.setUser(spELService.getSpELValue(method, logAnnotation.user(), String.class, parameterArgs));

        return log;
    }


}
